package com.skyline.energy.provider.skyline;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import com.skyline.energy.dataaccess.jdbc.KeyHolder;
import com.skyline.energy.exception.DataAccessException;
import com.skyline.energy.utils.JdbcUtils;

class BatchUpdateCallback implements PreparedStatementCallback<int[]> {
	private final KeyHolder generatedKeyHolder;
	private final List<Object[]> argsList;

	public BatchUpdateCallback(KeyHolder generatedKeyHolder, List<Object[]> argsList) {
		this.generatedKeyHolder = generatedKeyHolder;
		this.argsList = argsList;
	}

	@Override
	public int[] doInPreparedStatement(PreparedStatement ps) throws SQLException, DataAccessException {
		int batchSize = argsList.size();
		if (JdbcUtils.supportsBatchUpdates(ps.getConnection())) {
			for (int i = 0; i < batchSize; i++) {
				setParameterValue(ps, argsList, i);
				ps.addBatch();
			}
			int[] rows = ps.executeBatch();
			return processBatchResult(ps, rows, true, generatedKeyHolder);
		} else {
			List<Integer> rowsAffected = new ArrayList<Integer>();
			int[] rows = new int[1];
			for (int i = 0; i < batchSize; i++) {
				setParameterValue(ps, argsList, i);
				int rowAffected = ps.executeUpdate();
				rows[0] = rowAffected;
				rowsAffected.add(rowAffected);
				processBatchResult(ps, rows, (i == 0), generatedKeyHolder); // 第一次清空KeyHolder
			}
			return processAffectedArray(rowsAffected);
		}
	}

	private int[] processAffectedArray(List<Integer> rowsAffected) {
		int[] rowsAffectedArray = new int[rowsAffected.size()];
		for (int i = 0; i < rowsAffectedArray.length; i++) {
			rowsAffectedArray[i] = rowsAffected.get(i);
		}
		return rowsAffectedArray;
	}

	private int[] processBatchResult(PreparedStatement ps, int[] rows, boolean clearKeys,
			final KeyHolder generatedKeyHolder) throws SQLException {
		if (generatedKeyHolder != null) {
			List<Map<String, Object>> generatedKeys = generatedKeyHolder.getKeyList();
			if (clearKeys) {
				generatedKeys.clear();
			}
			ResultSet keys = ps.getGeneratedKeys();
			if (keys != null) {
				try {
					RowMapperResultSetExtractor<Map<String, Object>> rse = new RowMapperResultSetExtractor<Map<String, Object>>(
							new ColumnMapRowMapper(), rows.length);
					generatedKeys.addAll(rse.extractData(keys));
				} finally {
					JdbcUtils.closeResultSet(keys);
				}
			}
		}
		return rows;
	}

	private void setParameterValue(final PreparedStatement ps, final List<Object[]> argsList, int idx)
			throws SQLException {
		Object[] args = argsList.get(idx);
		if (args != null) {
			for (int index = 0; index < args.length; index++) {
				Object arg = args[index];
				JdbcUtils.setParameterValue(ps, index + 1, arg);
			}
		}
	}
}
